﻿////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// <copyright>Copyright 2008-2011 Andreas Huber Doenni</copyright>
// Distributed under the Microsoft Public License (Ms-PL).
// See accompanying file License.txt or copy at http://mews.codeplex.com/license.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

namespace Mews.Net.Nntp
{
    using System.Collections.Generic;
    using System.Text;

    /// <summary>Represents the command executed immediately after the connection to an NNTP server.</summary>
    internal sealed class ConnectCommand : NonPipelinableCommand<ConnectResponse>
    {
        private static readonly string[] successCodes = { "200", "201" };
        private static readonly byte[] modeReaderCommand = Encoding.UTF8.GetBytes("MODE READER");

        /// <summary>See <see cref="CommandBase{T, U}.SendCommand"/>.</summary>
        protected sealed override void SendCommand(CreateCommandStreamCallback createCommandStreamCallback)
        {
            // We intentionally don't send anything here.
        }

        /// <summary>See <see cref="NonPipelinableCommandBase{T, U}.ReceiveResponse"/>.</summary>
        protected sealed override ConnectResponse ReceiveResponse(
            CreateResponseStreamCallback createResponseStreamCallback,
            CreateCommandStreamCallback createCommandStreamCallback)
        {
            // Ignore response to initial connection, GIVEN that we get a response code indicating success
            createResponseStreamCallback(Encoding.UTF8, 2, successCodes).Dispose();

            // The following procedure is recommended for mode-switching RFC977 servers, see
            // http://www.ietf.org/rfc/rfc3977.txt, 3.4.2.
            using (var modeStream = createCommandStreamCallback(false))
            {
                modeStream.Write(modeReaderCommand, 0, modeReaderCommand.Length);
            }

            using (var modeResponseStream = createResponseStreamCallback(Encoding.UTF8, 2, successCodes))
            {
                return new ConnectResponse(modeResponseStream.InitialLineWords[0] == "200");
            }
        }

        /// <summary>See <see cref="NonPipelinableCommand{T}.ThrowOnError"/>.</summary>
        protected sealed override void ThrowOnError(IList<string> initialResponseLineWords)
        {
            if (initialResponseLineWords[0] == "502")
            {
                throw new ExceptionHelper(initialResponseLineWords).CreateException<ServiceUnavailableException>();
            }

            base.ThrowOnError(initialResponseLineWords);
        }
    }
}
